package com.shelpe.services.algorithm.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.beans.BeanUtils;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.shelpe.services.algorithm.client.InsightWordData;
import com.shelpe.services.algorithm.entity.batis.RptKeyword;
import com.shelpe.services.algorithm.repository.dto.semiauto.SemiautoCondition;
import com.shelpe.services.algorithm.repository.dto.semiauto.SemiautoDeleteModel;
import com.shelpe.services.algorithm.repository.dto.semiauto.SemiautoMatchScopeModel;
import com.shelpe.services.algorithm.repository.dto.semiauto.SemiautoPriceModel;
import com.shelpe.services.algorithm.repository.dto.semiauto.SemiautoSettings;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class SemiautoUtils {

	@SuppressWarnings("unchecked")
	public static SemiautoSettings unserializeSettings(String content) {
		SemiautoSettings settings = new SemiautoSettings();
		try {
			Map<String, Object> map = (Map<String, Object>) PHPSerializer.unserialize(content);
			log.debug("unserialize: {}", ToStringBuilder.reflectionToString(map));

			if (map != null) {
				if (map.containsKey("indexs")) {
					SemiautoUtils.toConditions(settings, (List<Object>) map.get("indexs"));
				}
				if (map.containsKey("priceModel")) {
					settings.setPriceModel(SemiautoUtils.toPriceModel((Map<String, Object>) map.get("priceModel")));;
				}
				if (map.containsKey("matchscopeModel")) {
					settings.setMatchScopeModel(SemiautoUtils.toMatchScopeModel((Map<String, Object>) map.get("matchscopeModel")));;
				}
				if (map.containsKey("delete")) {
					settings.setDeleteModel(SemiautoUtils.toDeleteModel((Map<String, Object>) map.get("delete")));;
				}
				if (map.containsKey("date")) {
					settings.setDate(NumberUtils.toInt(map.get("date").toString()));
				}
			}
		} catch (IllegalAccessException e) {
			log.error("IllegalAccessException: ", e);
		}
		return settings;
	}
	
	public static String serializeSettings(SemiautoSettings settings){
		Map<String, Object> map = new HashMap<String, Object>();
		List<Object> values = new ArrayList<Object>();
		for(SemiautoCondition cond: settings.getConditions()){
			values.add(SemiautoUtils.fromCondition(cond));
		}
		List<Object> indexs = new ArrayList<Object>();
		indexs.add(values);
		map.put("indexs", indexs);
		map.put("date", settings.getDate());
		map.put("delete", SemiautoUtils.fromDeleteModel(settings.getDeleteModel()));
		map.put("priceModel", SemiautoUtils.fromPriceModel(settings.getPriceModel()));
		map.put("matchscopeModel", SemiautoUtils.fromMatchScopeModel(settings.getMatchScopeModel()));
		byte[] buffer = PHPSerializer.serialize(map);
		return new String(buffer);
	}
	
	public static float pickup(String name, InsightWordData wordData){
		float value = 0;
		if(wordData == null){
			return value;
		}
		if("fav_count_rate".equals(name)){
			value = 100f * (wordData.getFavTotal()/wordData.getClick());
		}else{
			Field field = SemiautoUtils.findField(wordData, name);
			if(field !=null){
				try {
					String setterName = "get" + (name.substring(0, 1).toUpperCase()) + name.substring(1);
					Method method = BeanUtils.findMethod(wordData.getClass(), setterName);
					if(method != null){
						Object ret = method.invoke(wordData, null);
						if(ret != null){
							value = NumberUtils.toFloat(ret.toString());
						}
					}
					if("cost".equals(name)){
						value = value / 100;
					}
					
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		return value;
	}
	
	public static float pickup(String name, RptKeyword wordData){
		float value = 0;
		if(wordData == null){
			return value;
		}
		if("fav_count_rate".equals(name)){
			if(wordData.getFavItemCount() == null || wordData.getClick() == null){
				value = 0;
				return value;
			}
			value = 100f * (wordData.getFavItemCount()/wordData.getClick());
		}else{
			Field field = SemiautoUtils.findField(wordData, name);
			if(field !=null){
				try {
					String setterName = "get" + (name.substring(0, 1).toUpperCase()) + name.substring(1);
					Method method = BeanUtils.findMethod(wordData.getClass(), setterName);
					if(method != null){
						Object ret = method.invoke(wordData, null);
						if(ret != null){
							value = NumberUtils.toFloat(ret.toString());
						}
					}
					if("cost".equals(name)){
						value = value / 100;
					}
					
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		return value;
	}
	
	private static Field findField(Object wordData, String name){
		Field found = null;
		
		Field[] fields = wordData.getClass().getDeclaredFields();
		for(Field field: fields){
			if(field.getName().equals(name)){
				found = field;
				break;
			}
			JsonProperty jp = field.getAnnotation(JsonProperty.class);
			if(jp != null && jp.value().equals(name)){
				found = field;
				break;
			}
		}
		
		return found;
	}

	@SuppressWarnings("unchecked")
	private static void toConditions(SemiautoSettings settings, List<Object> values) {
		if(values == null){
			return;
		}
		values = (List<Object>) values.iterator().next();
		if(values == null){
			return;
		}
		for (Object value : values) {
			SemiautoCondition cond = SemiautoUtils.toCondition((Map<String, Object>) value);
			settings.addCondition(cond);
		}
	}

	private static SemiautoPriceModel toPriceModel(Map<String, Object> map) {
		SemiautoPriceModel model = new SemiautoPriceModel();
		if (map.containsKey("optionType") && map.get("optionType") != null) {
			model.setOptionType(NumberUtils.toInt(map.get("optionType").toString()));
		}
		if (map.containsKey("priceType") && map.get("priceType") != null) {
			model.setPriceType(NumberUtils.toInt(map.get("priceType").toString()));
		}
		if (map.containsKey("status") && map.get("status") != null) {
			model.setStatus(NumberUtils.toInt(map.get("status").toString()));
		}
		if (map.containsKey("priceValue") && map.get("priceValue") != null) {
			model.setPriceValue(NumberUtils.toFloat(map.get("priceValue").toString()));
		}
		if (map.containsKey("priceExtreme") && map.get("priceExtreme") != null) {
			model.setPriceExtreme(map.get("priceExtreme").toString());
		}
		return model;
	}
	
	private static Map<String, Object> fromPriceModel(SemiautoPriceModel model) {
		Map<String, Object> map = new HashMap<String, Object>();
		if(model != null){
			map.put("status", model.getStatus());
			map.put("optionType", model.getOptionType());
			map.put("priceType", model.getPriceType());
			map.put("priceValue", model.getPriceValue());
			map.put("priceExtreme", model.getPriceExtreme());
		}else{
			map.put("status", 0);
		}
		return map;
	}
	
	private static SemiautoMatchScopeModel toMatchScopeModel(Map<String, Object> map) {
		SemiautoMatchScopeModel model = new SemiautoMatchScopeModel();
		if (map.containsKey("value")) {
			model.setValue(NumberUtils.toInt(map.get("value").toString()));
		}
		if (map.containsKey("status")) {
			model.setStatus(NumberUtils.toInt(map.get("status").toString()));
		}
		return model;
	}
	
	private static Map<String, Object> fromMatchScopeModel(SemiautoMatchScopeModel model) {
		Map<String, Object> map = new HashMap<String, Object>();
		if(model != null){
			map.put("status", model.getStatus());
			map.put("value", model.getValue());
		}else{
			map.put("status", 0);
		}
		return map;
	}
	
	private static SemiautoDeleteModel toDeleteModel(Map<String, Object> map) {
		SemiautoDeleteModel model = new SemiautoDeleteModel();
		if (map.containsKey("status")) {
			model.setStatus(NumberUtils.toInt(map.get("status").toString()));
		}
		return model;
	}
	
	private static Map<String, Object> fromDeleteModel(SemiautoDeleteModel model) {
		Map<String, Object> map = new HashMap<String, Object>();
		if(model != null){
			map.put("status", model.getStatus());
		}else{
			map.put("status", 0);
		}
		return map;
	}

	private static SemiautoCondition toCondition(Map<String, Object> map) {
		SemiautoCondition cond = new SemiautoCondition();
		if (map.containsKey("intdex_value")) {
			cond.setValue(NumberUtils.toInt(map.get("intdex_value").toString()));
		}
		if (map.containsKey("intdex_depth")) {
			cond.setDepth(NumberUtils.toInt(map.get("intdex_depth").toString()));
		}
		if (map.containsKey("intdex_srouceType")) {
			cond.setSourceType(NumberUtils.toInt(map.get("intdex_srouceType").toString()));
		}
		if (map.containsKey("intdex_srouceValue")) {
			cond.setSourceValue(map.get("intdex_srouceValue").toString());
		}
		if (map.containsKey("intdex_condition")) {
			cond.setCondition(map.get("intdex_condition").toString());
		}
		if (map.containsKey("intdex_name")) {
			cond.setName(map.get("intdex_name").toString());
		}
		if (map.containsKey("intdex_method")) {
			cond.setMethod(map.get("intdex_method").toString());
		}
		return cond;
	}
	
	private static Map<String, Object> fromCondition(SemiautoCondition cond) {
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("intdex_value", cond.getValue());
		map.put("intdex_depth", cond.getDepth());
		map.put("intdex_srouceType", cond.getSourceType());
		if(cond.getSourceValue() != null){
			map.put("intdex_srouceValue", cond.getSourceValue());
		}
		if(cond.getCondition() != null){
			map.put("intdex_condition", cond.getCondition());
		}
		if(cond.getName() != null){
			map.put("intdex_name", cond.getName());
		}
		if(cond.getMethod() != null){
			map.put("intdex_method", cond.getMethod());
		}
		return map;
	}
	
//	public static void main(String[] args){
//		SemiautoSettings settings = new SemiautoSettings();
//		settings.setDate(5);
//		settings.setDeleteModel(new SemiautoDeleteModel());
//		settings.getDeleteModel().setStatus(0);
//		settings.setMatchScopeModel(new SemiautoMatchScopeModel());
//		settings.getMatchScopeModel().setStatus(1);
//		settings.getMatchScopeModel().setValue(2);
//		settings.setPriceModel(new SemiautoPriceModel());
//		settings.getPriceModel().setStatus(1);
//		settings.getPriceModel().setOptionType(1);
//		settings.getPriceModel().setPriceType(1);
//		settings.getPriceModel().setPriceValue(1.2f);
//		settings.getPriceModel().setPriceExtreme("3.3");
//		settings.setConditions(new ArrayList<SemiautoCondition>());
//		
//		SemiautoCondition cond = new SemiautoCondition();
//		cond.setName("roi");
//		cond.setCondition(">");
//		cond.setDepth(4);
//		cond.setMethod("and");
//		cond.setSourceType(3);
//		cond.setSourceValue("2.3");
//		cond.setValue(1);
//		settings.getConditions().add(cond);
//		cond = new SemiautoCondition();
//		cond.setName("ctr");
//		cond.setCondition("<");
//		cond.setDepth(4);
//		cond.setMethod("and");
//		cond.setSourceType(2);
//		cond.setValue(1);
//		settings.getConditions().add(cond);
//		
//		String str = SemiautoUtils.serializeSettings(settings);
//		System.out.println("str: " + str);
//		
//		SemiautoSettings settings_new = SemiautoUtils.unserializeSettings(str);
//		System.out.println("settings_new: " + settings_new);
//	}
	
}
